package com.jy.appmarket.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.webkit.URLUtil;

import com.jy.appmarket.R;
import com.jy.appmarket.model.AppInfoModel;
import com.jy.appmarket.network.engine.WidgetNetEngine;
import com.jy.appmarket.network.engine.cachestrategy.NamedCacheStrategy;
import com.jy.appmarket.network.resultdata.WidgetResultData;
import com.jy.appmarket.widget.entertainment.EntertainmentWidgetProvider;
import com.jy.appmarket.widget.games.GamesWidgetProvider;
import com.jy.appmarket.widget.tools.ToolsWidgetProvider;
import com.nostra13.universalimageloader.core.ImageLoader;

/**
 * 类说明：
 * 
 * @author Baker.li
 * @date 2014年8月29日
 * @version 1.0
 */

public class WidgetIconUtils {
	private static final String TAG = "WidgetIconUtils";
	public static final int TYPE_TOOL_WIDGET = 1;
	public static final int TYPE_GAME_WIDGET = 2;
	public static final int TYPE_ENTERTAINMENT_WIDGET = 3;

	public final static String TOOL_WIDGET_FILENAME = "tools_icon.png";
	public final static String GAME_WIDGET_FILENAME = "game_icon.png";
	public final static String ENTERTAINMENT_WIDGET_FILENAME = "entertainment_icon.png";

	private static WidgetIconUtils sInstance;

	private ImagesDownloadTask mToolTask;
	private ImagesDownloadTask mGameTask;
	private ImagesDownloadTask mEnterTask;

	public static WidgetIconUtils getInstance() {
		if (sInstance == null) {
			synchronized (WidgetIconUtils.class) {
				if (sInstance == null) {
					sInstance = new WidgetIconUtils();
				}
			}
		}
		return sInstance;
	}

	private WidgetIconUtils() {
		// hide the constructor
	}

	public static String getWidgetTypeName(int type) {
		if (type == TYPE_TOOL_WIDGET) {
			return "tool_widget";
		} else if (type == TYPE_GAME_WIDGET) {
			return "game_widget";
		} else if (type == TYPE_ENTERTAINMENT_WIDGET) {
			return "entertainment_widget";
		} else {
			return "unknown";
		}
	}

	public void initDefaultPackage(Context ctx) {
		try {
			if (ctx == null) {
				return;
			}
			if (Prefs.hasInitDefaultPackage(ctx)) {
				return;
			}
			Properties prop = new Properties();
			AssetManager am = ctx.getAssets();
			try {
				InputStream is = am.open("widget_default");
				prop.load(is);
			} catch (IOException ex) {
				Prefs.setInitDefaultPackage(ctx, true);
				return;
			}

			String keys[] = { "tool_default", "game_default", "entertainment_default" };
			for (String def : keys) {
				String value = (String) prop.get(def);
				if (value == null) {
					continue;
				}
				String ss[] = value.split(",");
				if (ss == null) {
					continue;
				}
				Set<String> set = new HashSet<String>();
				for (String s : ss) {
					if (PackageUtils.isPackageInstalled(ctx, s)) {
						set.add(s);
					}
				}
				if (set.size() == 0) {
					continue;
				}
				StringBuilder sb = new StringBuilder();
				for (String s : set) {
					sb.append(s).append("|");
				}
				sb.deleteCharAt(sb.length() - 1);
				String s = null;
				if (def.equals(keys[0])) {
					s = Prefs.getDesktopSoftware(ctx);
					if (TextUtils.isEmpty(s)) {
						Prefs.saveDesktopSoftware(ctx, sb.toString());
					}
				} else if (def.equals(keys[1])) {
					s = Prefs.getDesktopGame(ctx);
					if (TextUtils.isEmpty(s)) {
						Prefs.saveDesktopGame(ctx, sb.toString());
					}
				} else {
					s = Prefs.getDesktopEntertainment(ctx);
					if (TextUtils.isEmpty(s)) {
						Prefs.saveDesktopEntertainment(ctx, sb.toString());
					}
				}
			}
			Prefs.setInitDefaultPackage(ctx, true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private List<AppInfoModel> trimUninstalledApps(Context context, List<AppInfoModel> list) {
		List<AppInfoModel> uninstalledApps = new ArrayList<AppInfoModel>();
		for (AppInfoModel app : list) {
			if (!PackageUtils.isPackageInstalled(context, app.getPackageName())) {
				uninstalledApps.add(app);
			}
		}
		return uninstalledApps;
	}

	public String[] getUserSavedPackages(Context context, int type) {
		String split[] = null;
		String ss = null;
		if (type == TYPE_TOOL_WIDGET) {
			ss = Prefs.getDesktopSoftware(context);
		} else if (type == TYPE_GAME_WIDGET) {
			ss = Prefs.getDesktopGame(context);
		} else if (type == TYPE_ENTERTAINMENT_WIDGET) {
			ss = Prefs.getDesktopEntertainment(context);
		}
		if (!TextUtils.isEmpty(ss)) {
			split = ss.split("\\|");
		}
		return split;
	}

	public List<AppInfoModel> mergeWidgetList(Context ctx, List<AppInfoModel> recommends,
			String[] user) {
		List<AppInfoModel> apps = new ArrayList<AppInfoModel>();
		if (recommends != null && recommends.size() != 0) {
			for (AppInfoModel app : recommends) {
				apps.add(app);
			}
		}
		if (user != null && user.length != 0) {
			for (String pkg : user) {
				if (!TextUtils.isEmpty(pkg) && PackageUtils.isPackageInstalled(ctx, pkg)) {
					AppInfoModel app = new AppInfoModel();
					app.setInstalledApp(true);
					app.setPackageName(pkg);
					app.setName(PackageUtils.getApplicationName(ctx, pkg));
					apps.add(app);
				}
			}
		}
		return apps;
	}

	public List<AppInfoModel> trimRecommends(Context context, List<AppInfoModel> list) {
		if (context == null) {
			throw new IllegalArgumentException("context is null");
		}
		if (list == null || list.size() == 0) {
			return null;
		}
		List<AppInfoModel> apps = new ArrayList<AppInfoModel>();

		List<AppInfoModel> uninstalled = trimUninstalledApps(context, list);
		if (uninstalled.size() > 6) {
			uninstalled = uninstalled.subList(0, 6);
		}
		apps.addAll(uninstalled);
		return apps;

	}

	public List<String> getImageUrls(List<AppInfoModel> list) {
		if (list == null || list.size() == 0) {
			return null;
		}
		List<String> urls = new ArrayList<String>();
		for (AppInfoModel app : list) {
			if (URLUtil.isHttpUrl(app.getPic())) {
				urls.add(app.getPic());
			}
		}
		return urls;
	}

	public File getIconFile(Context ctx, int type) {
		File dir = ctx.getFilesDir();
		if (type == TYPE_TOOL_WIDGET) {
			return new File(dir, TOOL_WIDGET_FILENAME);
		} else if (type == TYPE_GAME_WIDGET) {
			return new File(dir, GAME_WIDGET_FILENAME);
		} else if (type == TYPE_ENTERTAINMENT_WIDGET) {
			return new File(dir, ENTERTAINMENT_WIDGET_FILENAME);
		}
		return new File(dir, TOOL_WIDGET_FILENAME);
	}

	public static final Bitmap createBitmap(Context ctx, List<Bitmap> bmps, boolean isNew) {
		if (bmps == null || bmps.size() > 9) {
			throw new IllegalArgumentException("bmps is null or has more than 9 items");
		}
		Bitmap[] icons = new Bitmap[bmps.size()];
		for (int i = 0; i < icons.length; i++) {
			if (bmps.get(i) == null) {
				Bitmap icon = BitmapFactory.decodeResource(ctx.getResources(),
						R.drawable.ic_launcher);
				icons[i] = icon;
			} else {
				icons[i] = bmps.get(i);
			}
		}
		Bitmap bg = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.widget_icon_bg);

		Bitmap bmp = Bitmap.createBitmap(bg.getWidth(), bg.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(bmp);

		Matrix matrix = new Matrix();
		canvas.drawBitmap(bg, matrix, null);

		int leftMargin = UITools.dip2px(ctx, 3);
		int topMargin = UITools.dip2px(ctx, 3);
		int space = UITools.dip2px(ctx, 3);
		int iconWidth = (canvas.getWidth() - leftMargin * 2 - space * 2) / 3;
		int iconHeight = (canvas.getHeight() - topMargin * 2 - space * 2) / 3;

		for (int i = 0; i < icons.length; i++) {
			int col = i % 3;
			int row = i / 3;
			int left = leftMargin + col * (iconWidth + space);
			int top = topMargin + row * (iconHeight + space);
			Rect rect = new Rect(left, top, left + iconWidth, top + iconHeight);
			canvas.drawBitmap(icons[i], null, rect, null);
		}
		if (isNew) {
			Bitmap newIcon = BitmapFactory
					.decodeResource(ctx.getResources(), R.drawable.widget_new);
			Rect rect = new Rect(bmp.getWidth() - newIcon.getWidth(), 0, bmp.getWidth(),
					newIcon.getHeight());
			canvas.drawBitmap(newIcon, null, rect, null);
		}

		canvas.save();
		return bmp;
	}

	private void createWidgetIconFile(Context context, List<AppInfoModel> list, int type,
			boolean isNew) {
		List<Bitmap> bmps = new ArrayList<Bitmap>();

		for (AppInfoModel app : list) {
			Bitmap bmp = null;
			if (app.isInstalledApp()) {
				bmp = BitmapUtils.getApplicationIconBitmap(context, app.getPackageName());
			} else {
				if (!TextUtils.isEmpty(app.getPic())) {
					File cache = new File(StorageConfig.CACHE_DIR, app.getPic().hashCode() + "");
					if (cache.exists()) {
						bmp = BitmapFactory.decodeFile(cache.getAbsolutePath());
					} else {
						LogUtil.w(TAG, "icon cache not found");
					}
				}
			}
			bmps.add(bmp);
		}
		if (bmps.size() > 9) {
			bmps = bmps.subList(0, 9);
		}
		Bitmap bmp = createBitmap(context, bmps, isNew);
		File file = getIconFile(context, type);
		BitmapUtils.saveBitmap2File(file, bmp);
		sendUpdateWidgetBroadcast(context, type);
	}

	public void sendUpdateWidgetBroadcast(Context ctx, int type) {
		Intent it = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
		AppWidgetManager am = AppWidgetManager.getInstance(ctx);
		String name = ToolsWidgetProvider.class.getName();
		if (type == TYPE_GAME_WIDGET) {
			name = GamesWidgetProvider.class.getName();
		} else if (type == TYPE_ENTERTAINMENT_WIDGET) {
			name = EntertainmentWidgetProvider.class.getName();
		}

		ComponentName cn = new ComponentName(ctx.getPackageName(), name);
		int[] ids = am.getAppWidgetIds(cn);
		if (ids != null && ids.length != 0) {
			Bundle extra = new Bundle();
			extra.putIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
			it.setComponent(cn);
			it.putExtras(extra);
			ctx.sendBroadcast(it);
		} else {
			LogUtil.d(TAG, "no widget to update:" + type);
		}
	}

	private void startDownloadIcons(Context context, String[] urls, List<AppInfoModel> list,
			int type, boolean isNew) {
		if (type == TYPE_TOOL_WIDGET) {
			if (mToolTask != null && mToolTask.getStatus() != AsyncTask.Status.FINISHED) {
				mToolTask.cancel(true);
			}
			mToolTask = new ImagesDownloadTask(context, list, type, isNew);
			mToolTask.execute(urls);

		} else if (type == TYPE_GAME_WIDGET) {
			if (mGameTask != null && mGameTask.getStatus() != AsyncTask.Status.FINISHED) {
				mGameTask.cancel(true);
			}
			mGameTask = new ImagesDownloadTask(context, list, type, isNew);
			mGameTask.execute(urls);
		} else if (type == TYPE_ENTERTAINMENT_WIDGET) {
			if (mEnterTask != null && mEnterTask.getStatus() != AsyncTask.Status.FINISHED) {
				mEnterTask.cancel(true);
			}
			mEnterTask = new ImagesDownloadTask(context, list, type, isNew);
			mEnterTask.execute(urls);
		} else {
			LogUtil.w(TAG, "unknown type:" + type);
		}
	}

	public void updateIcon(Context context, List<AppInfoModel> list, int type, boolean isNew) {
		if (context == null) {
			throw new IllegalArgumentException("context is null");
		}
		List<String> urls = getImageUrls(list);
		if (urls == null || urls.size() == 0) {
			// send broadcast
			LogUtil.d(TAG, "no icon to download");
			createWidgetIconFile(context, list, type, isNew);
		} else {
			String[] ss = urls.toArray(new String[urls.size()]);
			startDownloadIcons(context, ss, list, type, isNew);
		}
	}

	private class ImagesDownloadTask extends AsyncTask<String, Integer, Boolean> {
		private Context mContext;
		private List<AppInfoModel> mList;
		private int mType;
		private boolean mIsNew;

		public ImagesDownloadTask(Context context, List<AppInfoModel> list, int type, boolean isNew) {
			mContext = context;
			mList = list;
			mType = type;
			mIsNew = isNew;
		}

		@Override
		protected Boolean doInBackground(String... params) {
			for (String imgUrl : params) {
				Bitmap bmp = ImageLoader.getInstance().loadImageSync(imgUrl);
				if (bmp == null) {
					LogUtil.w(TAG, "get " + imgUrl + " failed");
				}
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (isCancelled()) {
					break;
				}
			}
			return true;
		}

		@Override
		protected void onPostExecute(Boolean result) {
			createWidgetIconFile(mContext, mList, mType, mIsNew);
		}
	}

	public void initWidgetCacheFromAssetsIfNecessary(Context ctx) {
		FileManager.createFileDir();
		if (ctx == null) {
			return;
		}
		String[] ss = { WidgetNetEngine.TYPE_TOOL, WidgetNetEngine.TYPE_GAME,
				WidgetNetEngine.TYPE_ENTERTAINMENT };
		for (String s : ss) {
			LogUtil.d(TAG, "init:" + s);
			NamedCacheStrategy cache = new NamedCacheStrategy(s);
			File file = cache.getCacheFile();
			if (!file.exists()) {
				copyFileFromAssets(ctx, s);
				WidgetResultData result = new WidgetResultData(s);
				try {
					file = new File(StorageConfig.CACHE_DIR, s);

					if (file.length() > 1024 * 100 || file.length() <= 0) {
						file.delete();
					} else {
						FileInputStream fis = new FileInputStream(file);
						byte[] bytes = new byte[(int) file.length()];
						fis.read(bytes);
						fis.close();
						String content = new String(bytes, "UTF-8");
						result.parseResult(content);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}

				WidgetIconUtils utils = WidgetIconUtils.getInstance();
				List<AppInfoModel> recommends = utils.trimRecommends(ctx, result == null ? null
						: result.getList());
				int type = WidgetIconUtils.TYPE_TOOL_WIDGET;
				if (s.equals(WidgetNetEngine.TYPE_GAME)) {
					type = WidgetIconUtils.TYPE_GAME_WIDGET;
				} else if (s.equals(WidgetNetEngine.TYPE_ENTERTAINMENT)) {
					type = WidgetIconUtils.TYPE_ENTERTAINMENT_WIDGET;
				}
				String[] user = utils.getUserSavedPackages(ctx, type);
				List<AppInfoModel> list = utils.mergeWidgetList(ctx, recommends, user);
				utils.updateIcon(ctx, list, type, true);
			}
		}
		copyCacheIcons(ctx);
	}

	private boolean copyFileFromAssets(Context context, String fileName) {
		if (context == null || fileName == null) {
			LogUtil.w(TAG, "context or fileName must be specified");
			return false;
		}
		AssetManager am = context.getAssets();
		try {
			InputStream stream = am.open(fileName);
			if (stream == null) {
				return false;
			}
			File file = new File(StorageConfig.CACHE_DIR, fileName);
			if (file.exists()) {
				file.delete();
			}
			FileOutputStream out = new FileOutputStream(file);
			IOTools.copyStream(stream, out);
			out.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	private void copyCacheIcons(Context ctx) {
		try {
			AssetManager am = ctx.getAssets();
			String[] files = am.list("cache");
			if (files == null) {
				return;
			}
			for (String f : files) {
				try {
					InputStream stream = am.open("cache/" + f);
					File file = new File(StorageConfig.CACHE_DIR, f);
					if (!file.exists()) {
						FileOutputStream out = new FileOutputStream(file);
						IOTools.copyStream(stream, out);
						out.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
